/*
 * This file is part of LangMan.
 *
 * LangMan is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * LangMan is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with LangMan.  If not, see <http://www.gnu.org/licenses/>.
 */

package langman.gui.profile;

import com.google.common.base.Strings;
import javafx.fxml.FXML;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ListView;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.stage.DirectoryChooser;
import javafx.stage.FileChooser;
import javafx.stage.FileChooser.ExtensionFilter;
import javafx.stage.Stage;
import langman.business.data.TranslationException;
import langman.business.profiles.Profile;
import langman.business.profiles.ProfileService;
import langman.gui.StageService;
import langman.util.doping.Inject;
import langman.util.doping.SingletonBean;
import langman.util.guifactory.AbstractFXMLBeanControl;
import langman.util.guifactory.GUIFactory;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.controlsfx.dialog.Dialogs;

import java.io.File;

@SingletonBean
public class ProfileControl extends AbstractFXMLBeanControl {
    private static final ExtensionFilter CONFIG_EXTENSION_FILTER = new ExtensionFilter("config", "*.lmx");
    private final GUIFactory        guiFactory;
    private final ProfileService    profileService;
    private final StageService      stageService;
    @FXML
    private       ListView<Profile> profileList;

    @FXML
    private Button addButton;

    @FXML
    private Button removeButton;

    @FXML
    private TextField nameTextField;

    @FXML
    private Button okButton;

    @FXML
    private GridPane editGrid;

    private Stage stage;

    private final Logger logger = LogManager.getLogger(getClass());
    private FileSelector rootFolderSelector;
    private FileSelector configFileSelector;

    private boolean exitedWithoutOK = true;

    @Inject
    public ProfileControl(GUIFactory guiFactory, ProfileService profileService, StageService stageService) {
        this.guiFactory = guiFactory;
        this.profileService = profileService;
        this.stageService = stageService;
    }

    @Override
    protected void initializeAfterInjection() {
        configureStage();
        stageService.setMainStage(stage);

        configureRootFolderSelector();
        configureConfigFileSelector();
        configureEditGrid();

        profileList.setItems(profileService.getProfilesUnmodifiable());

        profileList.getSelectionModel().selectedItemProperty().addListener((observableValue, oldValue, newValue) -> {
            if (oldValue != null) {
                nameTextField.textProperty().unbindBidirectional(oldValue.nameProperty());
            }

            if (newValue != null) {
                rootFolderSelector.setSelectedFile(newValue.getRootFolder());
                configFileSelector.setSelectedFile(newValue.getConfigFile());
                nameTextField.textProperty().bindBidirectional(newValue.nameProperty());
            }
        });

        profileList.setCellFactory(profileListView -> new ProfileListCell());

        if (!profileList.getItems().isEmpty()) {
            profileList.getSelectionModel().select(profileList.getItems().get(0));
        }

        profileList.requestFocus();

        configureButtons();
    }

    private void configureEditGrid() {
        editGrid.disableProperty().bind(profileList.getSelectionModel().selectedItemProperty().isNull());
        editGrid.add(rootFolderSelector.getNode(), 1, 1);
        editGrid.add(configFileSelector.getNode(), 1, 2);
    }

    private void configureRootFolderSelector() {
        rootFolderSelector = guiFactory.createControl(FileSelector.class);
        rootFolderSelector.setMode(FileSelectorMode.Directory);
        rootFolderSelector.selectedFileProperty().addListener((observableValue, oldValue, newValue) -> {
            if (newValue != null && newValue.canRead() && newValue.isDirectory()) {
                Profile selectedProfile = getSelectedProfile();
                selectedProfile.setRootFolder(newValue);
            }
        });
    }

    private void configureConfigFileSelector() {
        configFileSelector = guiFactory.createControl(FileSelector.class);
        configFileSelector.setMode(FileSelectorMode.File);
        configFileSelector.setExtensionFilters(CONFIG_EXTENSION_FILTER);

        configFileSelector.selectedFileProperty().addListener((observableValue, oldValue, newValue) -> {
            if (newValue != null && newValue.canRead() && !newValue.isDirectory()) {
                Profile selectedProfile = getSelectedProfile();
                selectedProfile.setConfigFile(newValue);
            }
        });
    }

    private Profile getSelectedProfile() {
        return profileList.getSelectionModel().getSelectedItem();
    }

    private void configureStage() {
        stage = new Stage();
        stage.setScene(new Scene(getNode()));
        stage.setTitle("Select Profile");
    }

    private void configureButtons() {
        okButton.setOnAction(actionEvent -> {
            try {
                profileService.writeProfileFile();
            } catch (TranslationException e) {
                logger.error(e.getMessage(), e);
            }
            exitedWithoutOK = false;
            stage.close();
        });
        okButton.disableProperty().bind(profileList.getSelectionModel().selectedItemProperty().isNull());

        addButton.setOnAction(actionEvent -> {
            createNewProfile();
        });

        removeButton.setOnAction(actionEvent -> {
            try {
                profileService.removeProfile(profileList.getSelectionModel().getSelectedItem());
            } catch (TranslationException e) {
                logger.error(e.getMessage(), e);
            }
        });
        removeButton.disableProperty().bind(profileList.getSelectionModel().selectedItemProperty().isNull());
    }

    private void createNewProfile() {
        try {
            String name = Dialogs.create().lightweight().owner(stage).message("Enter profile name:").showTextInput("New Profile");

            if (Strings.isNullOrEmpty(name)) {
                return;
            }

            DirectoryChooser directoryChooser = new DirectoryChooser();
            directoryChooser.setTitle("Choose root folder for languages");
            File rootDirectory = directoryChooser.showDialog(stage);

            if (rootDirectory == null || !rootDirectory.canRead() || !rootDirectory.isDirectory()) {
                return;
            }

            FileChooser fileChooser = new FileChooser();
            fileChooser.setTitle("Choose config file");
            fileChooser.getExtensionFilters().setAll(CONFIG_EXTENSION_FILTER);
            File configFile = fileChooser.showOpenDialog(stage);

            if (configFile == null || !configFile.canRead() || configFile.isDirectory()) {
                return;
            }

            Profile profile = new Profile(name, rootDirectory, configFile);
            profileService.addProfile(profile);
            profileList.getSelectionModel().select(profile);
        } catch (TranslationException e) {
            logger.error(e.getMessage(), e);
        }
    }

    public Profile showAndWait() {
        stage.showAndWait();
        return profileList.getSelectionModel().getSelectedItem();
    }

    public boolean isExitedWithoutOK() {
        return exitedWithoutOK;
    }
}
